package sceneObjects;

import utils.*;
import main.Intersection;
import main.Parseable;
import main.Parser;

public class Box extends abstractSceneObject implements sceneObject, Parseable {
    private Point3D p0, p1, p2, p3, p4, p5, p6;
    private RectPlane[] sides;

    @Override
    public boolean setParameter(String name, String[] args) {
	if (super.setParameter(name, args)) {
	    return true;
	} else if (name.equals("p0")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p0 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p1")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p1 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p2")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p2 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p3")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p3 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	}

	// We didn't find any parameter
	return false;
    }

    @Override
    public boolean finalizeObject() {
	if (!super.finalizeObject()) {
	    return false;
	}
	// Checks if the 3 points exists
	if (p0 == null || p1 == null || p2 == null || p3 == null) {
	    System.out.println("Error: Missing 4 points");
	    return false;
	}

	// Check that the 4 points aren't colinear
	if (GeoUtils.isCollinear(p0, p1, p2) || GeoUtils.isCollinear(p0, p1, p3) || GeoUtils.isCollinear(p0, p2, p3) || GeoUtils.isCollinear(p1, p2, p3)) {
	    System.out.println("Error: Rectangle points are colinear");
	    return false;
	}

	Vector v1 = new Vector(p0, p1);
	Vector v2 = new Vector(p0, p3);

	p4 = p3.addVector(v1);
	p5 = p2.addVector(v1);
	p6 = p2.addVector(v2);

	sides = new RectPlane[6];
	sides[0] = new RectPlane(p0, p1, p2);
	sides[1] = new RectPlane(p0, p3, p1);
	sides[2] = new RectPlane(p0, p2, p3);
	sides[3] = new RectPlane(p1, p4, p5);
	sides[4] = new RectPlane(p2, p5, p6);
	sides[5] = new RectPlane(p3, p6, p4);

	return true;
    }

    @Override
    public boolean isCamera() {
	return false;
    }

    public boolean isLight() {
	return false;
    }

    @Override
    public Intersection getIntersect(Ray ray) {
	Point3D minPoint = null;
	Point3D hitPoint = null;

	Intersection intersect;

	int hitSide = 0;
	double distance = Double.POSITIVE_INFINITY;
	double tempDistance;

	for (int i = 0; i < sides.length; i++) {
	    intersect = sides[i].getIntersect(ray);
	    if (intersect != null) {
		hitPoint = intersect.getPoint();
		if (hitPoint != null) {
		    tempDistance = ray.getSource().distance(hitPoint);
		    if (tempDistance < distance) {
			distance = tempDistance;
			minPoint = hitPoint;
			hitSide = i;
		    }
		}
	    }
	}

	if (minPoint == null) {
	    return null;
	} else {
	    return new Intersection(minPoint, this, hitSide);
	}
    }

    public Point3D getParameterization(Intersection intersect) {
	return sides[intersect.getExtraData()].getParameterization(intersect);
    }

    public Vector getNormalAtPoint(Intersection intersect) {
	return sides[intersect.getExtraData()].getNormalAtPoint(intersect);
    }
}
